/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
* This file is a part of the CANN Open Software.
* Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
* ===================================================================================================================*/
#include <gtest/gtest.h>
#include "ascend_ir/ascend_reg_ops.h"
#include "ascir_ops.h"
#include "ascend_ir/ascend_ir.h"
#include "ascend_ir/expression.h"
#include <iostream>
#include "graph/utils/node_utils_ex.h"

using namespace ge::ascir_op;
namespace {
constexpr int64_t ID_NONE = -1;

}
class UtestAscendIR : public testing::Test {
 protected:
  void SetUp() {}

  void TearDown() {}
};
using namespace ge;
using ge::expression::ExpressionPtr;
using ge::expression::Expression;

TEST_F(UtestAscendIR, TilingKey_OK) {
  AscGraph graph("test_graph");
  graph.SetTilingKey(10);
  EXPECT_EQ(graph.GetTilingKey(), 10);
}

TEST_F(UtestAscendIR, CreateAxis) {
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  s0_axis.align = 10;
  auto s0_axis_find = graph.FindAxis(s0_axis.id);
  EXPECT_NE(s0_axis_find, nullptr);
  EXPECT_EQ(s0_axis_find->name, "S0");
  EXPECT_EQ(s0_axis_find->align, 10);

  auto axis_invalid = graph.FindAxis(-1);
  EXPECT_EQ(axis_invalid, nullptr);
}

TEST_F(UtestAscendIR, BlockSplit) {
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  auto split_axis = graph.BlockSplit(s0_axis.id);
  EXPECT_NE(split_axis.first, nullptr);
  EXPECT_NE(split_axis.second, nullptr);
  auto &outer_axis = *split_axis.first;
  auto &inner_axis = *split_axis.second;
  EXPECT_EQ(inner_axis.type, Axis::AXIS_TYPE_BLOCK_INNER);
  EXPECT_EQ(outer_axis.type, Axis::AXIS_TYPE_BLOCK_OUTER);
}

TEST_F(UtestAscendIR, TileSplit) {
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  s0_axis.align = 10;
  auto split_axis = graph.TileSplit(s0_axis.id);
  EXPECT_NE(split_axis.first, nullptr);
  EXPECT_NE(split_axis.second, nullptr);
  auto &outer_axis = *split_axis.first;
  auto &inner_axis = *split_axis.second;
  EXPECT_EQ(inner_axis.type, Axis::AXIS_TYPE_TILE_INNER);
  EXPECT_EQ(outer_axis.type, Axis::AXIS_TYPE_TILE_OUTER);
}

TEST_F(UtestAscendIR, MergeAxis) {
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  const ExpressionPtr s1 = Expression::CreateExpression("s1");
  Axis &s1_axis = graph.CreateAxis("S1", s1);
  auto merge_axis = graph.MergeAxis({s0_axis.id, s1_axis.id});
  EXPECT_NE(merge_axis, nullptr);
  EXPECT_EQ(merge_axis->type, Axis::AXIS_TYPE_MERGED);
}

TEST_F(UtestAscendIR, GetAllAxisTransInfo) {
  AscGraph graph("test_graph");
  auto A = Expression::CreateExpression("A");
  auto B = Expression::CreateExpression("B");
  auto C = Expression::CreateExpression("C");
  auto a = graph.CreateAxis("a", A);
  auto b = graph.CreateAxis("b", B);
  auto c = graph.CreateAxis("c", C);
  auto [aBO, aBI] = graph.BlockSplit(a.id);
  EXPECT_EQ(graph.GetAllAxisTransInfo().size(), 1U);
  EXPECT_EQ(graph.GetAllAxisTransInfo().front().trans_type, TransType::kSplit);
  EXPECT_EQ(graph.GetAllAxisTransInfo().front().src_axis.size(), 1U);
  EXPECT_EQ(graph.GetAllAxisTransInfo().front().src_axis.front()->id, a.id);
  EXPECT_EQ(graph.GetAllAxisTransInfo().front().dst_axis.size(), 2U);
  EXPECT_EQ(graph.GetAllAxisTransInfo().front().dst_axis, std::vector<AxisPtr>({aBO, aBI}));
  auto aBIb = graph.MergeAxis({aBI->id, b.id});
  EXPECT_EQ(graph.GetAllAxisTransInfo().size(), 2U);
  EXPECT_EQ(graph.GetAllAxisTransInfo()[1U].trans_type, TransType::kMerge);
  EXPECT_EQ(graph.GetAllAxis().size(), 6U);
}

TEST_F(UtestAscendIR, ApplySplit) {
  auto ONE = Expression::CreateExpression(1);
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  ascir_op::Data data("data", graph);
  auto data_node = ge::NodeUtilsEx::GetNodeFromOperator(data);
  EXPECT_NE(data_node, nullptr);
  data.attr.sched.exec_order = 1;
  data.attr.sched.axis = {s0_axis.id};
  data.y.dtype = ge::DT_FLOAT16;
  data.y.format = ge::FORMAT_ND;
  *data.y.axis = {s0_axis.id};
  *data.y.repeats = {s0};
  *data.y.strides = {ONE};

  auto split_axis = graph.TileSplit(s0_axis.id);
  EXPECT_NE(split_axis.first, nullptr);
  EXPECT_NE(split_axis.second, nullptr);
  auto &outer_axis = *split_axis.first;
  auto &inner_axis = *split_axis.second;
  EXPECT_EQ(inner_axis.type, Axis::AXIS_TYPE_TILE_INNER);
  EXPECT_EQ(outer_axis.type, Axis::AXIS_TYPE_TILE_OUTER);

  auto data_node_find = graph.FindNode("data");
  EXPECT_NE(data_node_find, nullptr);
  graph.ApplySplit(data_node_find, outer_axis.id, inner_axis.id);
}

TEST_F(UtestAscendIR, ApplyMerge_0_not_merge_tensor_but_merge_node) {
  auto ONE = Expression::CreateExpression(1);
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  const ExpressionPtr s1 = Expression::CreateExpression("s1");
  Axis &s1_axis = graph.CreateAxis("S1", s1);
  ascir_op::Data data("data", graph);
  auto data_node = ge::NodeUtilsEx::GetNodeFromOperator(data);
  EXPECT_NE(data_node, nullptr);
  data.attr.sched.exec_order = 1;
  data.attr.sched.axis = {s0_axis.id, s1_axis.id};
  data.y.dtype = ge::DT_FLOAT16;
  data.y.format = ge::FORMAT_ND;
  *data.y.axis = {s0_axis.id, s1_axis.id};
  *data.y.repeats = {s0, s1};
  *data.y.strides = {ONE, ONE};

  auto merge_axis = graph.MergeAxis({s0_axis.id, s1_axis.id});
  EXPECT_NE(merge_axis, nullptr);
  EXPECT_EQ(merge_axis->type, Axis::AXIS_TYPE_MERGED);

  auto data_node_find = graph.FindNode("data");
  EXPECT_NE(data_node_find, nullptr);
  graph.ApplyMerge(data_node_find, merge_axis->id);
  EXPECT_EQ(data_node_find->attr.sched.axis.size(), 1U);
  EXPECT_EQ(data_node_find->outputs[0].axis.size(), 2U);
}

TEST_F(UtestAscendIR, ApplyMerge_1) {
  auto ONE = Expression::CreateExpression(1);
  auto ZERO = Expression::CreateExpression(0);
  AscGraph graph("test_graph");
  const auto s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  const auto s1 = Expression::CreateExpression("s1");
  Axis &s1_axis = graph.CreateAxis("S1", s1);
  ascir_op::Data data("data", graph);
  auto data_node = ge::NodeUtilsEx::GetNodeFromOperator(data);
  EXPECT_NE(data_node, nullptr);
  data.attr.sched.exec_order = 1;
  data.attr.sched.axis = {s0_axis.id, s1_axis.id};
  data.y.dtype = ge::DT_FLOAT16;
  data.y.format = ge::FORMAT_ND;
  *data.y.axis = {s0_axis.id, s1_axis.id};
  *data.y.repeats = {s0, s1};
  *data.y.strides = {s1, ONE};

  auto merge_axis = graph.MergeAxis({s0_axis.id, s1_axis.id});
  EXPECT_NE(merge_axis, nullptr);
  EXPECT_EQ(merge_axis->type, Axis::AXIS_TYPE_MERGED);

  auto data_node_find = graph.FindNode("data");
  EXPECT_NE(data_node_find, nullptr);
  graph.ApplyMerge(data_node_find, merge_axis->id);
  EXPECT_EQ(data_node_find->attr.sched.axis.size(), 1U);
  EXPECT_EQ(data_node_find->outputs[0].axis.size(), 1U);
  EXPECT_EQ(data_node_find->outputs[0].repeats.size(), 1U);
  EXPECT_EQ(*(data_node_find->outputs[0].repeats[0U]), *(s0*s1));
  EXPECT_EQ(*(data_node_find->outputs[0].repeats[0U]), *(s0*s1));
  EXPECT_EQ(*(data_node_find->outputs[0].strides[0U]), *ONE);
}

TEST_F(UtestAscendIR, ApplyReorder) {
  auto ONE = Expression::CreateExpression(1);
  AscGraph graph("test_graph");
  const ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);
  const ExpressionPtr s1 = Expression::CreateExpression("s1");
  Axis &s1_axis = graph.CreateAxis("S1", s1);
  ascir_op::Data data("data", graph);
  auto data_node = ge::NodeUtilsEx::GetNodeFromOperator(data);
  EXPECT_NE(data_node, nullptr);
  data.attr.sched.exec_order = 1;
  data.attr.sched.axis = {s0_axis.id, s1_axis.id};
  data.y.dtype = ge::DT_FLOAT16;
  data.y.format = ge::FORMAT_ND;
  *data.y.axis = {s0_axis.id, s1_axis.id};
  *data.y.repeats = {s0, s1};
  *data.y.strides = {s1, ONE};

  auto data_node_find = graph.FindNode("data");
  EXPECT_NE(data_node_find, nullptr);
  graph.ApplyReorder(data_node_find, {s1_axis.id, s0_axis.id});
}


TEST_F(UtestAscendIR, CreateOptional) {
  AscGraph graph("test_graph");
  (void)graph.CreateOptionalAtt("a", 0U, 1, 2);
  (void)graph.CreateOptionalAtt("a", 0U, 1U, 2U);
  (void)graph.CreateOptionalAtt("a", 0U, 1.0f, 2.0f);
  (void)graph.CreateOptionalAtt("a", 0U, static_cast<int8_t>(1), static_cast<int8_t>(2));
  (void)graph.CreateOptionalAtt("a", 0U, "int32_t", "1", "2");
  auto op_all = graph.GetAllOptional();
  EXPECT_EQ(op_all.size(), 5U);
  EXPECT_EQ(op_all[0]->idx, 0U);
  EXPECT_EQ(op_all[0]->name, "a");
  EXPECT_EQ(op_all[0]->data_type, "int32_t");
  EXPECT_EQ(op_all[0]->min_value, "1");
  EXPECT_EQ(op_all[0]->max_value, "2");
}

TEST_F(UtestAscendIR, Operator_OK) {
  auto ONE = Expression::CreateExpression(1);
  AscGraph graph("test_graph");
  ExpressionPtr s0 = Expression::CreateExpression("s0");
  Axis &s0_axis = graph.CreateAxis("S0", s0);

  ascir_op::Data data("data", graph);
  auto data_node = ge::NodeUtilsEx::GetNodeFromOperator(data);
  EXPECT_NE(data_node, nullptr);
  data.attr.sched.exec_order = 1;
  data.attr.sched.axis = {s0_axis.id};
  data.y.dtype = ge::DT_FLOAT16;
  data.y.format = ge::FORMAT_ND;
  *data.y.axis = {s0_axis.id};
  *data.y.repeats = {s0};
  *data.y.strides = {ONE};

  ascir_op::Abs abs("abs");
  auto abs_node = ge::NodeUtilsEx::GetNodeFromOperator(abs);
  EXPECT_EQ(abs_node, nullptr);
  abs.x = data.y;
  abs_node = ge::NodeUtilsEx::GetNodeFromOperator(abs);
  EXPECT_NE(abs_node, nullptr);

  // find Node
  auto data_node_find = graph.FindNode("data");
  EXPECT_NE(data_node_find, nullptr);
  EXPECT_EQ(data_node_find->attr.sched.exec_order, 1);
  EXPECT_EQ(data_node_find->attr.sched.axis.size(), 1U);
  EXPECT_EQ(data_node_find->attr.sched.axis[0], s0_axis.id);
  EXPECT_EQ(data_node_find->outputs[0].axis.size(), 1);
  EXPECT_EQ(ge::DataType(data_node_find->outputs[0].dtype), ge::DT_FLOAT16);
  EXPECT_EQ(ge::Format(data_node_find->outputs[0].format), ge::FORMAT_ND);
  auto abs_node_find = graph.FindNode("abs");
  EXPECT_NE(abs_node_find, nullptr);

  // GetAllNodes
  int num = 0;
  for (const auto &node : graph.GetAllNodes()) {
    if (num == 0) {
      EXPECT_EQ(node->GetName(), "data");      
      EXPECT_EQ(node->attr.sched.exec_order, 1);
      EXPECT_EQ(node->attr.sched.axis.size(), 1U);
      EXPECT_EQ(node->attr.sched.axis[0], s0_axis.id);
      EXPECT_EQ(node->outputs[0].axis.size(), 1);
      const auto outputs = node->outputs();
      EXPECT_EQ(outputs.size(), 1U);
      EXPECT_NE(outputs[0], nullptr);
      EXPECT_EQ(outputs[0]->axis.size(), 1);
    }
    if (num == 1) {
      EXPECT_EQ(node->inputs.Size(), 1U); 
      EXPECT_EQ(node->inputs[0].axis.size(), 1);
    }
    num++;
  }
  EXPECT_EQ(num, 2);

  // GetAllNodes
  int input_nodes_num = 0;
  for (auto node : graph.GetInputNodes()) {
    if (input_nodes_num == 0) {
      EXPECT_EQ(node->GetName(), "data");      
      EXPECT_EQ(node->attr.sched.exec_order, 1);
      EXPECT_EQ(node->attr.sched.axis.size(), 1U);
      EXPECT_EQ(node->attr.sched.axis[0], s0_axis.id);
      EXPECT_EQ(node->outputs[0].axis.size(), 1);
    }
    input_nodes_num++;
  }
  EXPECT_EQ(input_nodes_num, 1);
  EXPECT_EQ(graph.GetName(), "test_graph");

  // GetAllAxis
  const AscGraph &const_graph = graph;
  const auto all_axis = const_graph.GetAllAxis();
  EXPECT_EQ(all_axis.size(), 1U);
}

TEST_F(UtestAscendIR, Operator_Fail) {
  bool catch_except = false;
  graphStatus status = GRAPH_SUCCESS;
  std::string error_info = "((src_node) != nullptr)";
  std::string error_info_get;
  try {
    ascir_op::Abs abs("abs");
    ascir_op::Output output("output");
    output.x = abs.y;
  } catch (const AscIRException &e) {
    catch_except = true;
    status = e.GetInfo().error_code;
    error_info_get = e.GetInfo().error_msg;
  }
  EXPECT_TRUE(catch_except == true);
  EXPECT_EQ(status, GRAPH_FAILED);
}

TEST_F(UtestAscendIR, GetNodeFailed) {
  AscGraph graph("test_graph");
  constexpr char kNodeName[] = "data";
  ascir_op::Data data(kNodeName, graph);
  EXPECT_THROW(graph.Node("data1"), std::exception);
  EXPECT_EQ(graph.Node(kNodeName).GetType(), "Data");
}

void Add_Layer_Norm_Normal_BeforeAutofuse(AscGraph &graph) {
  auto ONE = ge::expression::Expression::CreateExpression(1);
  auto ZERO = ge::expression::Expression::CreateExpression(0);
  // 定义轴的大小
  auto A = ge::expression::Expression::CreateExpression("A");
  auto R = ge::expression::Expression::CreateExpression("R");
  auto BL = ge::expression::Expression::CreateExpression(8, "BL");

  // 定义轴
  auto a = graph.CreateAxis("A", A);
  auto r = graph.CreateAxis("R", R);
  auto bl = graph.CreateAxis("BL", BL);

  // 定义节点
  int exec_order = 0;
  Data x1("x1", graph);
  x1.attr.sched.exec_order = exec_order++;
  x1.attr.sched.axis = {a.id, r.id, bl.id};
  x1.y.dtype = ge::DT_FLOAT16;
  *x1.y.axis = {a.id, r.id, bl.id};
  *x1.y.repeats = {A, R, ONE};
  *x1.y.strides = {R, ONE, ZERO};

  Load x1Local("x1Local");
  x1Local.x = x1.y;
  x1Local.attr.sched.exec_order = exec_order++;
  x1Local.attr.sched.axis = {a.id, r.id, bl.id};
  x1Local.y.dtype = ge::DT_FLOAT16;
  *x1Local.y.axis = {a.id, r.id, bl.id};
  *x1Local.y.repeats = {A, R, ONE};
  *x1Local.y.strides = {R, ONE, ZERO};

  Data x2("x2", graph);
  x2.attr.sched.exec_order = exec_order++;
  x2.attr.sched.axis = {a.id, r.id, bl.id};
  x2.y.dtype = ge::DT_FLOAT16;
  *x2.y.axis = {a.id, r.id, bl.id};
  *x2.y.repeats = {A, R, ONE};
  *x2.y.strides = {R, ONE, ZERO};

  Load x2Local("x2Local");
  x2Local.x = x2.y;
  x2Local.attr.sched.exec_order = exec_order++;
  x2Local.attr.sched.axis = {a.id, r.id, bl.id};
  x2Local.y.dtype = ge::DT_FLOAT16;
  *x2Local.y.axis = {a.id, r.id, bl.id};
  *x2Local.y.repeats = {A, R, ONE};
  *x2Local.y.strides = {R, ONE, ZERO};

  Data bias("bias", graph);
  bias.attr.sched.exec_order = exec_order++;
  bias.attr.sched.axis = {a.id, r.id, bl.id};
  bias.y.dtype = ge::DT_FLOAT16;
  *bias.y.axis = {a.id, r.id, bl.id};
  *bias.y.repeats = {A, R, ONE};
  *bias.y.strides = {R, ONE, ZERO};

  Load biasLocal("biasLocal");
  biasLocal.x = bias.y;
  biasLocal.attr.sched.exec_order = exec_order++;
  biasLocal.attr.sched.axis = {a.id, r.id, bl.id};
  biasLocal.y.dtype = ge::DT_FLOAT16;
  *biasLocal.y.axis = {a.id, r.id, bl.id};
  *biasLocal.y.repeats = {A, R, ONE};
  *biasLocal.y.strides = {R, ONE, ZERO};

  CalcMean mean("mean");
  mean.x1 = x1Local.y;
  mean.x2 = x2Local.y;
  mean.x3 = biasLocal.y;
  mean.attr.sched.exec_order = exec_order++;
  mean.attr.sched.axis = {a.id, r.id, bl.id};
  mean.y1.dtype = ge::DT_FLOAT;        // mean
  *mean.y1.axis = {a.id, r.id, bl.id};
  *mean.y1.repeats = {A, ONE, ONE};
  *mean.y1.strides = {ONE, ZERO, ZERO};
  mean.y2.dtype = ge::DT_FLOAT16;        // x out
  *mean.y2.axis = {a.id, r.id, bl.id};
  *mean.y2.repeats = {A, R, ONE};
  *mean.y2.strides = {R, ONE, ZERO};
  mean.y3.dtype = ge::DT_FLOAT;        // x fp32
  *mean.y3.axis = {a.id, r.id, bl.id};
  *mean.y3.repeats = {A, R, ONE};
  *mean.y3.strides = {R, ONE, ZERO};

  Store x_out("x_out");
  x_out.attr.sched.exec_order = exec_order++;
  x_out.attr.sched.axis = {a.id, r.id, bl.id};
  x_out.x = mean.y2;
  x_out.y.dtype = ge::DT_FLOAT16;
  *x_out.y.axis = {a.id, r.id, bl.id};
  *x_out.y.repeats = {A, R, ONE};
  *x_out.y.strides = {R, ONE, ZERO};

  Store mean_out("mean_out");
  mean_out.attr.sched.exec_order = exec_order++;
  mean_out.attr.sched.axis = {a.id, r.id, bl.id};
  mean_out.x = mean.y1;
  mean_out.y.dtype = ge::DT_FLOAT;
  *mean_out.y.axis = {a.id, r.id, bl.id};
  *mean_out.y.repeats = {A, ONE, ONE};
  *mean_out.y.strides = {ONE, ZERO, ZERO};

  TbufData one("one", graph);
  one.attr.sched.exec_order = exec_order++;
  one.attr.sched.axis = {a.id, r.id, bl.id};
  one.y.dtype = ge::DT_FLOAT;
  *one.y.axis = {a.id, r.id, bl.id};
  *one.y.repeats = {ONE, ONE, BL};
  *one.y.strides = {ZERO, ZERO, ONE};

  CalcRstd rstd("rstd");
  rstd.attr.sched.exec_order = exec_order++;
  rstd.attr.sched.axis = {a.id, r.id, bl.id};
  rstd.x1 = mean.y3;
  rstd.x2 = mean.y1;
  rstd.x3 = one.y;
  rstd.y1.dtype = ge::DT_FLOAT;      // x-mean
  *rstd.y1.axis = {a.id, r.id, bl.id};
  *rstd.y1.repeats = {A, R, ONE};
  *rstd.y1.strides = {R, ONE, ZERO};
  rstd.y2.dtype = ge::DT_FLOAT;     // rstd
  *rstd.y2.axis = {a.id, r.id, bl.id};
  *rstd.y2.repeats = {A, ONE, ONE};
  *rstd.y2.strides = {ONE, ZERO, ZERO};

  Store rstd_out("rstd_out");
  rstd_out.attr.sched.exec_order = exec_order++;
  rstd_out.attr.sched.axis = {a.id, r.id, bl.id};
  rstd_out.x = rstd.y2;
  rstd_out.y.dtype = ge::DT_FLOAT;
  *rstd_out.y.axis = {a.id, r.id, bl.id};
  *rstd_out.y.repeats = {A, ONE, ONE};
  *rstd_out.y.strides = {ONE, ZERO, ZERO};

  Data beta("beta", graph);
  beta.attr.sched.exec_order = exec_order++;
  beta.attr.sched.axis = {a.id, r.id, bl.id};
  beta.y.dtype = ge::DT_FLOAT16;
  *beta.y.axis = {a.id, r.id, bl.id};
  *beta.y.repeats = {ONE, R, ONE};
  *beta.y.strides = {ZERO, ONE, ZERO};

  Load betaLocal("betaLocal");
  betaLocal.x = beta.y;
  betaLocal.attr.sched.exec_order = exec_order++;
  betaLocal.attr.sched.axis = {a.id, r.id, bl.id};
  betaLocal.y.dtype = ge::DT_FLOAT16;
  *betaLocal.y.axis = {a.id, r.id, bl.id};
  *betaLocal.y.repeats = {ONE, R, ONE};
  *betaLocal.y.strides = {ZERO, ONE, ZERO};

  Data gamma("gamma", graph);
  gamma.attr.sched.exec_order = exec_order++;
  gamma.attr.sched.axis = {a.id, r.id, bl.id};
  gamma.y.dtype = ge::DT_FLOAT16;
  *gamma.y.axis = {a.id, r.id, bl.id};
  *gamma.y.repeats = {ONE, R, ONE};
  *gamma.y.strides = {ZERO, ONE, ZERO};

  Load gammaLocal("gammaLocal");
  gammaLocal.x = gamma.y;
  gammaLocal.attr.sched.exec_order = exec_order++;
  gammaLocal.attr.sched.axis = {a.id, r.id, bl.id};
  gammaLocal.y.dtype = ge::DT_FLOAT16;
  *gammaLocal.y.axis = {a.id, r.id, bl.id};
  *gammaLocal.y.repeats = {ONE, R, ONE};
  *gammaLocal.y.strides = {ZERO, ONE, ZERO};

  CalcY y("y");
  y.attr.sched.exec_order = exec_order++;
  y.attr.sched.axis = {a.id, r.id, bl.id};
  y.x1 = rstd.y1;                 // x-mean
  y.x2 = betaLocal.y;
  y.x3 = gammaLocal.y;
  y.x4 = rstd.y2;                 // rstd
  y.y1.dtype = ge::DT_FLOAT16;
  *y.y1.axis = {a.id, r.id, bl.id};
  *y.y1.repeats = {A, R, ONE};
  *y.y1.strides = {R, ONE, ZERO};

  Store y_out("y_out");
  y_out.attr.sched.exec_order = exec_order++;
  y_out.attr.sched.axis = {a.id, r.id, bl.id};
  y_out.x = y.y1;
  y_out.y.dtype = ge::DT_FLOAT16;
  *y_out.y.axis = {a.id, r.id, bl.id};
  *y_out.y.repeats = {A, R, ONE};
  *y_out.y.strides = {R, ONE, ZERO};

  Output buf1("buf1");
  buf1.x = x_out.y;
  buf1.attr.sched.exec_order = exec_order++;
  buf1.y.dtype = ge::DT_FLOAT16;
  *buf1.y.axis = {a.id, r.id, bl.id};
  *buf1.y.repeats = {A, R, ONE};
  *buf1.y.strides = {R, ONE, ZERO};

  Output buf2("buf2");
  buf2.x = mean_out.y;
  buf2.attr.sched.exec_order = exec_order++;
  buf2.y.dtype = ge::DT_FLOAT;
  *buf2.y.axis = {a.id, r.id, bl.id};
  *buf2.y.repeats = {A, ONE, ONE};
  *buf2.y.strides = {ONE, ZERO, ZERO};

  Output buf3("buf3");
  buf3.x = rstd_out.y;
  buf3.attr.sched.exec_order = exec_order++;
  buf3.y.dtype = ge::DT_FLOAT;
  *buf3.y.axis = {a.id, r.id, bl.id};
  *buf3.y.repeats = {A, ONE, ONE};
  *buf3.y.strides = {ONE, ZERO, ZERO};

  Output buf("buf");
  buf.x = y_out.y;
  buf.attr.sched.exec_order = exec_order++;
  buf.y.dtype = ge::DT_FLOAT16;
  *buf.y.axis = {a.id, r.id, bl.id};
  *buf.y.repeats = {A, R, ONE};
  *buf.y.strides = {R, ONE, ZERO};
}

/*
for aBO
  for aBIO
    for aBII
      for r
        load x1
        load x2
        load bias
        CalcMean
        CalcRstd
        Store X
        Store mean
        Load beta
        Load gamma
        CalcRstd
        Store rstd
        CalcY
        Store y
*/

void Add_Layer_Norm_Normal_AfterScheduler(AscGraph &graph) {
  auto a = graph.FindAxis(0)->id;
  auto r = graph.FindAxis(1)->id;

  auto [aBO, aBI] = graph.BlockSplit(a, "nbo", "nbi");   // AB Ab
  auto [aBIO, aBII] = graph.TileSplit(aBI->id, "nio", "nii");  // AbT Abt
  // graph.UpdateAxisAlign(aBI.id, 1u);
  // graph.UpdateAxisAlign(aBII.id, 8u);
  auto x1 = graph.FindNode("x1");
  graph.ApplySplit(x1, aBO->id, aBI->id);
  graph.ApplySplit(x1, aBIO->id, aBII->id);
  x1->attr.sched.loop_axis = aBIO->id;
  x1->outputs[0].vectorized_axis = {aBII->id, r};

  auto x2 = graph.FindNode("x2");
  graph.ApplySplit(x2, aBO->id, aBI->id);
  graph.ApplySplit(x2, aBIO->id, aBII->id);
  x2->attr.sched.loop_axis = aBIO->id;
  x2->outputs[0].vectorized_axis = {aBII->id, r};

  auto bias = graph.FindNode("bias");
  graph.ApplySplit(bias, aBO->id, aBI->id);
  graph.ApplySplit(bias, aBIO->id, aBII->id);
  bias->attr.sched.loop_axis = aBIO->id;
  bias->outputs[0].vectorized_axis = {aBII->id, r};

  auto x1Local = graph.FindNode("x1Local");
  graph.ApplySplit(x1Local, aBO->id, aBI->id);
  graph.ApplySplit(x1Local, aBIO->id, aBII->id);
  x1Local->attr.sched.loop_axis = aBIO->id;
  x1Local->outputs[0].vectorized_axis = {aBII->id, r};

  auto x2Local = graph.FindNode("x2Local");
  graph.ApplySplit(x2Local, aBO->id, aBI->id);
  graph.ApplySplit(x2Local, aBIO->id, aBII->id);
  x2Local->attr.sched.loop_axis = aBIO->id;
  x2Local->outputs[0].vectorized_axis = {aBII->id, r};

  auto biasLocal = graph.FindNode("biasLocal");
  graph.ApplySplit(biasLocal,aBO->id, aBI->id);
  graph.ApplySplit(biasLocal, aBIO->id, aBII->id);
  biasLocal->attr.sched.loop_axis = aBIO->id;
  biasLocal->outputs[0].vectorized_axis = {aBII->id, r};

  auto mean = graph.FindNode("mean");
  graph.ApplySplit(mean,aBO->id, aBI->id);
  graph.ApplySplit(mean,aBIO->id, aBII->id);
  mean->attr.sched.loop_axis = aBIO->id;
  mean->outputs[0].vectorized_axis = {aBII->id, r};
  mean->outputs[1].vectorized_axis = {aBII->id, r};
  mean->outputs[2].vectorized_axis = {aBII->id, r};

  auto x_out = graph.FindNode("x_out");
  graph.ApplySplit(x_out, aBO->id, aBI->id);
  graph.ApplySplit(x_out, aBIO->id, aBII->id);
  x_out->attr.sched.loop_axis = aBIO->id;
  x_out->outputs[0].vectorized_axis = {aBII->id, r};

  auto mean_out = graph.FindNode("mean_out");
  graph.ApplySplit(mean_out, aBO->id, aBI->id);
  graph.ApplySplit(mean_out, aBIO->id, aBII->id);
  mean_out->attr.sched.loop_axis = aBIO->id;
  mean_out->outputs[0].vectorized_axis = {aBII->id, r};

  auto rstd = graph.FindNode("rstd");
  graph.ApplySplit(rstd,aBO->id, aBI->id);
  graph.ApplySplit(rstd,aBIO->id, aBII->id);
  rstd->attr.sched.loop_axis = aBIO->id;
  rstd->outputs[0].vectorized_axis = {aBII->id, r};
  rstd->outputs[1].vectorized_axis = {aBII->id, r};

  auto rstd_out = graph.FindNode("rstd_out");
  graph.ApplySplit(rstd_out,aBO->id, aBI->id);
  graph.ApplySplit(rstd_out,aBIO->id, aBII->id);
  rstd_out->attr.sched.loop_axis = aBIO->id;
  rstd_out->outputs[0].vectorized_axis = {aBII->id, r};

  auto betaLocal = graph.FindNode("betaLocal");
  graph.ApplySplit(betaLocal,aBO->id, aBI->id);
  graph.ApplySplit(betaLocal,aBIO->id, aBII->id);
  betaLocal->attr.sched.loop_axis = aBIO->id;
  betaLocal->outputs[0].vectorized_axis = {r};

  auto gammaLocal = graph.FindNode("gammaLocal");
  graph.ApplySplit(gammaLocal,aBO->id, aBI->id);
  graph.ApplySplit(gammaLocal,aBIO->id, aBII->id);
  gammaLocal->attr.sched.loop_axis = aBIO->id;
  gammaLocal->outputs[0].vectorized_axis = {r};

  auto y = graph.FindNode("y");
  graph.ApplySplit(y,aBO->id, aBI->id);
  graph.ApplySplit(y,aBIO->id, aBII->id);
  y->attr.sched.loop_axis = aBIO->id;
  y->outputs[0].vectorized_axis = {aBII->id, r};

  auto y_out = graph.FindNode("y_out");
  graph.ApplySplit(y_out,aBO->id, aBI->id);
  graph.ApplySplit(y_out,aBIO->id, aBII->id);
  y_out->attr.sched.loop_axis = aBIO->id;
  y_out->outputs[0].vectorized_axis = {aBII->id, r};
}

void Add_Layer_Norm_Normal_AfterQueBufAlloc(AscGraph &graph) {
  int tensorID = 0;
  int queID = 0;
  int bufID = 0;
  int x1Que = queID++;
  int x2Que = queID++;
  int biasQue = queID++;
  int gammaQue = queID++;
  int betaQue = queID++;
  int meanQue = queID++;
  int rstdQue = queID++;
  int yQue = queID++;
  int xQue = queID++;
  int x32Queue = queID++;
  int oneTBuf = bufID++;

  auto x1 = graph.FindNode("x1");
  x1->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  x1->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto x2 = graph.FindNode("x2");
  x2->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  x2->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto bias = graph.FindNode("bias");
  bias->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  bias->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto x1Local = graph.FindNode("x1Local");
  x1Local->outputs[0].mem.tensor_id = tensorID++;
  x1Local->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  x1Local->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  x1Local->outputs[0].mem.position = ge::Position::POSITION_VECIN;
  x1Local->outputs[0].buf.id = ID_NONE;
  x1Local->outputs[0].que.id = x1Que;
  x1Local->outputs[0].que.depth = 1;
  x1Local->outputs[0].que.buf_num = 1;
  x1Local->outputs[0].opt.ref_tensor = ID_NONE;
  x1Local->outputs[0].opt.merge_scope = ID_NONE;

  auto x2Local = graph.FindNode("x2Local");
  x2Local->outputs[0].mem.tensor_id = tensorID++;
  x2Local->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  x2Local->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  x2Local->outputs[0].mem.position = ge::Position::POSITION_VECIN;
  x2Local->outputs[0].buf.id = ID_NONE;
  x2Local->outputs[0].que.id = x2Que;
  x2Local->outputs[0].que.depth = 1;
  x2Local->outputs[0].que.buf_num = 1;
  x2Local->outputs[0].opt.ref_tensor = ID_NONE;
  x2Local->outputs[0].opt.merge_scope = ID_NONE;

  auto biasLocal = graph.FindNode("biasLocal");
  biasLocal->outputs[0].mem.tensor_id = tensorID++;
  biasLocal->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  biasLocal->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  biasLocal->outputs[0].mem.position = ge::Position::POSITION_VECIN;
  biasLocal->outputs[0].buf.id = ID_NONE;
  biasLocal->outputs[0].que.id = biasQue;
  biasLocal->outputs[0].que.depth = 1;
  biasLocal->outputs[0].que.buf_num = 1;
  biasLocal->outputs[0].opt.ref_tensor = ID_NONE;
  biasLocal->outputs[0].opt.merge_scope = ID_NONE;

  auto mean = graph.FindNode("mean");
  mean->outputs[0].mem.tensor_id = tensorID++;
  mean->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  mean->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  mean->outputs[0].mem.position = ge::Position::POSITION_VECOUT;
  mean->outputs[0].buf.id = ID_NONE;
  mean->outputs[0].que.id = meanQue;
  mean->outputs[0].que.depth = 1;
  mean->outputs[0].que.buf_num = 1;
  mean->outputs[0].opt.ref_tensor = ID_NONE;
  mean->outputs[0].opt.merge_scope = ID_NONE;
  mean->outputs[1].mem.tensor_id = tensorID++;
  mean->outputs[1].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  mean->outputs[1].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  mean->outputs[1].mem.position = ge::Position::POSITION_VECOUT;
  mean->outputs[1].buf.id = ID_NONE;
  mean->outputs[1].que.id = xQue;
  mean->outputs[1].que.depth = 1;
  mean->outputs[1].que.buf_num = 1;
  mean->outputs[1].opt.ref_tensor = ID_NONE;
  mean->outputs[1].opt.merge_scope = ID_NONE;
  mean->outputs[2].mem.tensor_id = tensorID++;
  mean->outputs[2].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  mean->outputs[2].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  mean->outputs[2].mem.position = ge::Position::POSITION_VECOUT;
  mean->outputs[2].buf.id = ID_NONE;
  mean->outputs[2].que.id = x32Queue;
  mean->outputs[2].que.depth = 1;
  mean->outputs[2].que.buf_num = 1;
  mean->outputs[2].opt.ref_tensor = ID_NONE;
  mean->outputs[2].opt.merge_scope = ID_NONE;

  auto x_out = graph.FindNode("x_out");
  x_out->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  x_out->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto mean_out = graph.FindNode("mean_out");
  mean_out->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  mean_out->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto one = graph.FindNode("one");
  one->outputs[0].mem.tensor_id = tensorID++;
  one->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_BUFFER;
  one->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  one->outputs[0].mem.position = ge::Position::POSITION_VECIN;
  one->outputs[0].buf.id = oneTBuf;
  one->outputs[0].que.id = ID_NONE;
  one->outputs[0].que.depth = ID_NONE;
  one->outputs[0].que.buf_num = ID_NONE;
  one->outputs[0].opt.ref_tensor = ID_NONE;
  one->outputs[0].opt.merge_scope = ID_NONE;

  auto rstd = graph.FindNode("rstd");
  rstd->outputs[0].mem.tensor_id = tensorID++;
  rstd->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  rstd->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  rstd->outputs[0].mem.position = ge::Position::POSITION_VECOUT;
  rstd->outputs[0].buf.id =ID_NONE;
  rstd->outputs[0].que.id = yQue;
  rstd->outputs[0].que.depth = 1;
  rstd->outputs[0].que.buf_num = 1;
  rstd->outputs[0].opt.ref_tensor = ID_NONE;
  rstd->outputs[0].opt.merge_scope = ID_NONE;
  rstd->outputs[1].mem.tensor_id = tensorID++;
  rstd->outputs[1].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  rstd->outputs[1].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  rstd->outputs[1].mem.position = ge::Position::POSITION_VECOUT;
  rstd->outputs[1].buf.id = ID_NONE;
  rstd->outputs[1].que.id = rstdQue;
  rstd->outputs[1].que.depth = 1;
  rstd->outputs[1].que.buf_num = 1;
  rstd->outputs[1].opt.ref_tensor = ID_NONE;
  rstd->outputs[1].opt.merge_scope = ID_NONE;

  auto rstd_out = graph.FindNode("rstd_out");
  rstd_out->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  rstd_out->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto beta = graph.FindNode("beta");
  beta->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  beta->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto betaLocal = graph.FindNode("betaLocal");
  betaLocal->outputs[0].mem.tensor_id = tensorID++;
  betaLocal->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  betaLocal->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  betaLocal->outputs[0].mem.position = ge::Position::POSITION_VECIN;
  betaLocal->outputs[0].buf.id = ID_NONE;
  betaLocal->outputs[0].que.id = betaQue;
  betaLocal->outputs[0].que.depth = 1;
  betaLocal->outputs[0].que.buf_num = 1;
  betaLocal->outputs[0].opt.ref_tensor = ID_NONE;
  betaLocal->outputs[0].opt.merge_scope = ID_NONE;

  auto gamma = graph.FindNode("gamma");
  gamma->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  gamma->outputs[0].mem.position = ge::Position::POSITION_GM;

  auto gammaLocal = graph.FindNode("gammaLocal");
  gammaLocal->outputs[0].mem.tensor_id = tensorID++;
  gammaLocal->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  gammaLocal->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  gammaLocal->outputs[0].mem.position = ge::Position::POSITION_VECIN;
  gammaLocal->outputs[0].buf.id = ID_NONE;
  gammaLocal->outputs[0].que.id = gammaQue;
  gammaLocal->outputs[0].que.depth = 1;
  gammaLocal->outputs[0].que.buf_num = 1;
  gammaLocal->outputs[0].opt.ref_tensor = ID_NONE;
  gammaLocal->outputs[0].opt.merge_scope = ID_NONE;

  auto y = graph.FindNode("y");
  y->outputs[0].mem.tensor_id = tensorID++;
  y->outputs[0].mem.alloc_type = ge::AllocType::ALLOC_TYPE_QUEUE;
  y->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_UB;
  y->outputs[0].mem.position = ge::Position::POSITION_VECOUT;
  y->outputs[0].buf.id = ID_NONE;
  y->outputs[0].que.id = yQue;
  y->outputs[0].que.depth = 1;
  y->outputs[0].que.buf_num = 1;
  y->outputs[0].opt.ref_tensor = ID_NONE;
  y->outputs[0].opt.merge_scope = ID_NONE;

  auto y_out = graph.FindNode("y_out");
  y_out->outputs[0].mem.hardware = ge::MemHardware::MEM_HARDWARE_GM;
  y_out->outputs[0].mem.position = ge::Position::POSITION_GM;
}

TEST_F(UtestAscendIR, CheckValid) {
  AscGraph graph_normal("graph_normal");
  graph_normal.SetTilingKey(1101u);
  Add_Layer_Norm_Normal_BeforeAutofuse(graph_normal);
  Add_Layer_Norm_Normal_AfterScheduler(graph_normal);
  Add_Layer_Norm_Normal_AfterQueBufAlloc(graph_normal);
  EXPECT_EQ(graph_normal.CheckValid(), true);
  auto betaLocal = graph_normal.FindNode("betaLocal");
  betaLocal->outputs[0].que.id = ID_NONE;
  EXPECT_EQ(graph_normal.CheckValid(), false);
}
TEST_F(UtestAscendIR, CreateContiguousData) {
  AscGraph graph("test_graph");
  auto A = Expression::CreateExpression("A");
  auto B = Expression::CreateExpression("B");
  auto C = Expression::CreateExpression("C");
  auto D = Expression::CreateExpression("d");
  auto a = graph.CreateAxis("a", A);
  auto b = graph.CreateAxis("b", B);
  auto c = graph.CreateAxis("c", C);
  auto d = graph.CreateAxis("d", D);
  auto data = graph.CreateContiguousData("data0", ge::DT_INT8, {a});
  EXPECT_EQ(data.output_index, 0U);
  EXPECT_EQ(static_cast<ge::DataType>(data.dtype), ge::DT_INT8);
  EXPECT_EQ(data.format, ge::FORMAT_ND);
  EXPECT_EQ(*data.axis, std::vector<int64_t>({a.id}));
  const auto *attr = dynamic_cast< ge::ascir_op::Data::AscDataNodeAttr *>(&(graph.Node("data0").attr));
  EXPECT_EQ(attr->index, 0U);
  EXPECT_EQ(attr->format, ge::FORMAT_ND);
  EXPECT_EQ(attr->axis_continuous_map, std::vector<std::vector<int64_t>>({{0, -1}}));
  EXPECT_EQ(attr->sched.exec_order, 0U);
  EXPECT_EQ(attr->sched.loop_axis, -1);
  EXPECT_EQ(attr->sched.initial_axis.size(), 0U);

  auto data1 = graph.CreateContiguousData("data1", ge::DT_FLOAT, {a, b}, {{0, -2}, {-1}}, ge::FORMAT_DHWCN);
  EXPECT_EQ(data1.output_index, 0U);
  EXPECT_EQ(static_cast<ge::DataType>(data1.dtype), ge::DT_FLOAT);
  EXPECT_EQ(data1.format, ge::FORMAT_DHWCN);
  EXPECT_EQ(*data1.axis, std::vector<int64_t>({a.id, b.id}));
  const auto *attr1 = dynamic_cast< ge::ascir_op::Data::AscDataNodeAttr *>(&(graph.Node("data1").attr));
  EXPECT_EQ(attr1->index, 1U);
  EXPECT_EQ(attr1->format, ge::FORMAT_DHWCN);
  EXPECT_EQ(attr1->axis_continuous_map, std::vector<std::vector<int64_t>>({{0, -2}, {-1}}));
  EXPECT_EQ(attr1->sched.exec_order, 1U);
  EXPECT_EQ(attr1->sched.loop_axis, -1);
  EXPECT_EQ(attr1->sched.initial_axis.size(), 0U);
}

TEST_F(UtestAscendIR, CreateContiguousData_failed) {
  AscGraph graph("test_graph");
  auto A = Expression::CreateExpression("A");
  auto B = Expression::CreateExpression("B");
  auto C = Expression::CreateExpression("C");
  auto D = Expression::CreateExpression("d");
  auto a = graph.CreateAxis("a", A);
  auto b = graph.CreateAxis("b", B);
  auto c = graph.CreateAxis("c", C);
  auto d = graph.CreateAxis("d", D);
  EXPECT_THROW(graph.CreateContiguousData("data1", ge::DT_FLOAT, {a, b, c, d}, {{0, -2}, {-1}}, ge::FORMAT_DHWCN),
               std::exception);
}

TEST_F(UtestAscendIR, CreateContiguousOut) {
  AscGraph graph("test_graph");
  auto A = Expression::CreateExpression("A");
  auto B = Expression::CreateExpression("B");
  auto C = Expression::CreateExpression("C");
  auto D = Expression::CreateExpression("d");
  auto a = graph.CreateAxis("a", A);
  auto b = graph.CreateAxis("b", B);
  auto c = graph.CreateAxis("c", C);
  auto d = graph.CreateAxis("d", D);
  auto output1 = graph.CreateContiguousOut("out1", ge::DT_FLOAT16, {a, b}, ge::FORMAT_ND);

  EXPECT_EQ(output1.output_index, 0U);
  EXPECT_EQ(static_cast<ge::DataType>(output1.dtype), ge::DT_FLOAT16);
  EXPECT_EQ(output1.format, ge::FORMAT_ND);
  const auto *attr1 = dynamic_cast< AscNodeAttr *>(&(graph.Node("out1").attr));
  EXPECT_EQ(attr1->sched.exec_order, -1);
  EXPECT_EQ(attr1->sched.loop_axis, -1);
  EXPECT_EQ(attr1->sched.initial_axis.size(), 0U);
}

TEST_F(UtestAscendIR, StoreToOut) {
  AscGraph graph("test_graph");
  auto A = Expression::CreateExpression("A");
  auto B = Expression::CreateExpression("B");
  auto C = Expression::CreateExpression("C");
  auto D = Expression::CreateExpression("d");
  auto a = graph.CreateAxis("a", A);
  auto b = graph.CreateAxis("b", B);
  auto c = graph.CreateAxis("c", C);
  auto d = graph.CreateAxis("d", D);
  auto data1 = graph.CreateContiguousData("data1", ge::DT_FLOAT, {a, b}, {{0, -2}, {-1}}, ge::FORMAT_DHWCN);
  auto output1 = graph.CreateContiguousOut("out1", ge::DT_FLOAT16, {a, b, c}, ge::FORMAT_ND);
  auto load1 = ascir::cg::Load("load1", data1);
  ascir::cg::Store("StoreLoad1ToOutput1", load1, output1);
  EXPECT_EQ(output1.GetOwnerOp().GetInputsSize(), 1U);
  EXPECT_EQ(output1.output_index, 0U);
  EXPECT_EQ(static_cast<ge::DataType>(output1.dtype), ge::DT_FLOAT16);
  EXPECT_EQ(output1.format, ge::FORMAT_ND);
  EXPECT_EQ(*output1.axis, std::vector<int64_t>({a.id, b.id, c.id}));
  const auto *attr1 = dynamic_cast< AscNodeAttr *>(&(graph.Node("out1").attr));
  EXPECT_EQ(attr1->sched.exec_order, 3);
  EXPECT_EQ(attr1->sched.loop_axis, -1);
  EXPECT_EQ(attr1->sched.initial_axis.size(), 0U);
}
